/******************************************************************************
 * SAGE - Scalable Adaptive Graphics Environment
 *
 * Module: sageBase.h
 * Author : Byungil Jeong
 *
 * Copyright (C) 2004 Electronic Visualization Laboratory,
 * University of Illinois at Chicago
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either Version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License along
 * with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Direct questions, comments etc about SAGE to bijeong@evl.uic.edu or 
 * http://www.evl.uic.edu/cavern/forum/
 *
 *****************************************************************************/

#ifndef _SAGE_BASE_H
#define _SAGE_BASE_H

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <vector>
#include <algorithm>
#include <numeric>
#include <pthread.h>
#include <string.h>

#ifdef WIN32
	#include <io.h>
	#include <time.h>
	#include <process.h>
	
	#define _WIN32_WINNT    0x0501  // Macro for getting the switchToThread() to work
	#ifdef N_PLAT_NLM
		#include <ws2nlm.h>
	#else
		#include <winsock2.h>
	#endif
	#include <ws2tcpip.h>
	#include <windows.h>

#else
	#include <strings.h>
	#include <sys/time.h>
	#include <unistd.h>
	#include <sys/types.h>
	#include <sys/wait.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <arpa/inet.h>
	#include <netinet/tcp.h>
	#include <sys/stat.h>
	#include <sys/uio.h>	
#endif

#define SAGE_IP_LEN 128
#define SAGE_MAX_DOMAIN 10
#define SAGE_CMD_LEN 1024
#define SAGE_NAME_LEN 256
#define MAX_TILES_PER_NODE 9
#define TRACKING_DATA_SIZE 256
#define SAGE_PERF_START 10
#define CMAN_MSG_SIZE 2048
#define DISPLAY_BUF_NUM 2
#define BRIDGE_BUF_NUM  5

#define MESSAGE_HEADER_SIZE 36
#define MESSAGE_FIELD_SIZE 9

#define TOP_TO_BOTTOM 0
#define BOTTOM_TO_TOP 1

typedef unsigned sageApiOption;
#define SAGE_BLOCKING     1
#define SAGE_NON_BLOCKING 2
#define SAGE_BACKWARD     4

enum nwProtocol {SAGE_TCP, SAGE_UDP, LAMBDA_STREAM};
enum sageStreamMode {SAGE_RCV, SAGE_SEND, SAGE_BRIDGE};
enum sagePixFmt {PIXFMT_NULL, PIXFMT_555, PIXFMT_555_INV, PIXFMT_565, PIXFMT_565_INV, 
		PIXFMT_888, PIXFMT_888_INV, PIXFMT_8888, PIXFMT_8888_INV, PIXFMT_RLE, PIXFMT_LUV,
		PIXFMT_DXT, PIXFMT_YUV};
enum sageCompressType {NO_COMP, RLE_COMP, LUV_COMP, DXT_COMP};

enum sageSampleFmt {SAGE_SAMPLE_FLOAT32, SAGE_SAMPLE_INT16, SAGE_SAMPLE_INT8, SAGE_SAMPLE_UINT8};
enum sageAudioMode {SAGE_AUDIO_CAPTURE = 1, SAGE_AUDIO_PLAY = 2, SAGE_AUDIO_READ = 4, SAGE_AUDIO_WRITE = 8, SAGE_AUDIO_APP = 16, SAGE_AUDIO_FWCAPTURE = 32};
enum sageSyncType {SAGE_SYNC_NONE, SAGE_SYNC_AUDIO_DRIVEN, SAGE_SYNC_GRAPHIC_DRIVEN};


class sageRect {
public:	
	int x, y, width, height;
	float left, right, bottom, top;
	sageRect() : x(0), y(0), width(0), height(0), 
		left(0.0), right(1.0), bottom(0.0), top(1.0) {}
		
	sageRect(float l, float r, float b, float t) 
		: x(0), y(0), width(0), height(0), 
		left(l), right(r), bottom(b), top(t) {}

	sageRect(int rx, int ry, int rw, int rh) 
		: x(rx), y(ry), width(rw), height(rh), 
		left(0.0), right(1.0), bottom(0.0), top(1.0) {}
		
	~sageRect() {}

	void operator+= (sageRect &rect);
	sageRect operator+ (sageRect &rect);
	sageRect operator/ (float div);
	sageRect operator/ (sageRect &rect);
	void operator/= (sageRect &rect);
	sageRect operator* (sageRect &rect);
	void operator*= (sageRect &rect);
	
	void updateBoundary();
	void updateBoundary(sageRect &rect);
	void moveOrigin(sageRect &rect);
	void scale(float sx, float sy);
	void translate(int x, int y);
	void translate(sageRect &rect);
	void shrink(float x, float y);
	void locate();
	int normalize(sageRect &rect);
	int normalize(float x, float y);
	
	bool isOverLap(float l, float r, float b, float t, sageRect &com);
	bool isOverLapX(float l, float r, sageRect &com);
	bool isOverLapY(float b, float t, sageRect &com);

	bool isOverLap(sageRect &rect);	
	bool isOverLap(sageRect &rect, sageRect &com);
	bool isOverLapX(int x2, int w2, sageRect &com);
	bool isOverLapY(int y2, int h2, sageRect &com);

	bool isInRect(float x, float y);
	bool isInRect(sageRect &rect);
	void printRect();
	//int mask(sageRect &rect);  // crop by the rect which has normalized coordinates
};

class pixelBlock : public sageRect {
public:
	int numIOVs;
	struct iovec *iovs;
	
	pixelBlock() : numIOVs(0), iovs(NULL){ width = 64, height = 64; }
	void clearBlock();
	~pixelBlock();
};

#define BLOCK_HEADER_SIZE 128
#define SAGE_PIXEL_BLOCK   1
#define SAGE_BUFFER_BLOCK	2
#define SAGE_IOVEC_FRAME   3
#define SAGE_RLE_BLOCK		4
#define SAGE_AUDIO_BLOCK	5

#define SAGE_INIT_BLOCK	100
#define SAGE_STOP_BLOCK 101
#define SAGE_TIME_BLOCK	102
#define SAGE_ACK_BLOCK	103
#define SAGE_UPDATE_BLOCK 104

class sageChildBlock;

class sageBlock : public sageRect {
public:
	char header[BLOCK_HEADER_SIZE];
	char controlData[BLOCK_HEADER_SIZE];
	void *buffer; // starting address of image buffer

	int flag;		//	specify the function of block
	int blockType; // specify the type of block
	int frameNum;  // frame to which this block belongs
	sagePixFmt pixelType;   // pixel format of block
	sageRect dispRect;
	int subBlockNum, subWidth, subHeight;
	pixelBlock 	*subBlocks;
	
	//sageBlock *subGroups;
	//int subGroupNum;
	
	// variables to be used for block processing
	int bufSize;	// image buffer size
	float bytesPerPixel;
    int streamIdx;
	bool reformatted;
	int rowOrd;
	
	sageBlock() : buffer(NULL), flag(0), bytesPerPixel(3), frameNum(0), 
			pixelType(PIXFMT_888), subBlockNum(0), subWidth(0), subHeight(0),
			bufSize(0), subBlocks(NULL), reformatted(false), rowOrd(BOTTOM_TO_TOP) {}
	~sageBlock();

	void clearBlock();
	int initBuffer();
	int initBuffer(int size);
	int updateDataHeader();
	int updateControlHeader(char *data);	
	int updateConfig();
	int releaseBuffer();
	int resetBuffer() { buffer = NULL; }
	int computeBlockRect(int maxX, int maxY);
	//int generateSubGroup(sageRect &subRect, int id);
	int generatePixelBlocks(int rowOrder);
	int reconfigSageBlock();
	int generateChildBlock(sageRect &subRect, sageChildBlock &child);
};

class sageChildBlock : public sageRect {
public:
	char header[BLOCK_HEADER_SIZE];
	sageBlock *parent;
	std::vector<int> subBlockList;
	int bufOffset, bufLen;
	
	sageChildBlock() : parent(NULL), bufOffset(0), bufLen(0) {}
	~sageChildBlock() { parent = NULL; }
	
	int computeBlockRect();
	int updateHeader();
};

class sageMessage {
private:
	char *dest;
   char *code;
	char *appCode;
	char *size;
	
	void *data;
	char *buffer;
	int bufSize;
	int clientID;

public:
   sageMessage();
   ~sageMessage();
	// init by message contents
   int init(int dst, int co, int app, int sz, const void *dat);
	// init by message buffer size
	//void init();
	int init(int);
	int destroy(); 
	int set(int dst, int co, int app, int sz, const void *dat);
	int getDest();
	int getCode();
	int getAppCode();
	int getSize();
	int getBufSize() { return bufSize; }
	void* getData();
	char* getBuffer();
	int getClientID() { return clientID; }
	
	int setDest(int);
	int setCode(int);
	int setAppCode(int);
	int setSize(int s);
	int setData(int, void*);
	void setClientID(int id) { clientID = id; }
};

class appInExec : public sageRect {
public:	
	int uiClient;
	int sailClient;
	char appName[SAGE_NAME_LEN];
	int instID;
	nwProtocol protocol;
	int nwID;
	char fsIP[SAGE_IP_LEN];
	int fsPort;
	
	int bandWidth;
	char renderNodeIP[SAGE_IP_LEN];
};		

class sageAudioBlock {
public:
        char header[BLOCK_HEADER_SIZE];
        char controlData[BLOCK_HEADER_SIZE];
        void *buffer;   // starting address of audio buffer

        int flag;               //      specify the function of block   ???
        int blockType;  // specify the type of block            ???
        int frameNum;   // frame to which this block belongs
        int graphicNum; // frame to which this block belongs
        sageSampleFmt sampleFmt;   // sample format of block
        long sampleRate;
        int channels;
        int framePerBuffer;

        // variables to be used for block processing
        int bufSize;    // block buffer size

        int numIOVs;

        struct iovec *iovs;

        int bytesPerSample;
        bool reformatted;

        sageAudioBlock() : buffer(NULL), flag(0), bytesPerSample(4), frameNum(0),
                        sampleFmt(SAGE_SAMPLE_FLOAT32), sampleRate(0), channels(0), framePerBuffer(0),
                        bufSize(0), reformatted(false), numIOVs(0), iovs(NULL), graphicNum(0) {}
        ~sageAudioBlock();

        void clearBlock();
        int initBuffer();
        int initBuffer(int size);
        int updateDataHeader();
        int updateControlHeader(char *data);
        int updateConfig();
        int releaseBuffer();
        int generateBlocks();
};

#include "misc.h"

#endif
